﻿using Microsoft.Extensions.Logging;
using Sgr.Caching.Services;
using Sgr.Domain.Entities;
using Sgr.Organizations;
using Sgr.UPMS.Application.ViewModels;
using Sgr.UPMS.Domain.Departments;
using Sgr.UPMS.Domain.Duties;
using Sgr.UPMS.Domain.Organizations;

namespace Sgr.UPMS.Application.Services
{
    public class OrgDataCacheService : IOrgBasicDataCacheService, IOrganizationProvider
    {
        private readonly ICacheManager _cacheManager;
        private readonly IUpmsQueryContext _context;
        private readonly ILogger<OrgDataCacheService> _logger;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="cacheManager">缓存管理器</param>
        /// <param name="context">查询上下文</param>
        /// <param name="logger">日志记录器</param>
        public OrgDataCacheService(ICacheManager cacheManager, IUpmsQueryContext context, ILogger<OrgDataCacheService> logger)
        {
            _cacheManager = cacheManager ?? throw new ArgumentNullException(nameof(cacheManager));
            _context = context ?? throw new ArgumentNullException(nameof(context));
            _logger = logger ?? throw new ArgumentNullException(nameof(logger));
        }

        #region IOrganizationProvider

        public async Task<OrganizationInfo?> GetByIdAsync(string orgId, CancellationToken ct = default)
        {
            if (string.IsNullOrWhiteSpace(orgId))
                return null;

            if (!long.TryParse(orgId, out long id))
                throw new ArgumentException("Invalid orgId", nameof(orgId));

            return await GetOrgByKeyAsync(id, ct);
        }

        private async Task<OrganizationInfo?> GetOrgByKeyAsync(long orgId, CancellationToken ct = default)
        {
            if (orgId <= 0)
                throw new ArgumentException("Invalid orgId", nameof(orgId));

            var item = await _cacheManager.GetAsync(
                CacheKeys.GetOrgKey(orgId),
                async () =>
                {
                    try
                    {
                        return await LoadOrgAsync(orgId, ct);
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError(ex, "Error getting organization info for orgId: {OrgId}", orgId);
                        return null;
                    }
                },
                CacheKeys.CreateOrgBasicDataCacheOptions(),
                ct);

            return item;
        }

        #endregion IOrganizationProvider

        #region IOrgBasicDataCacheService

        /// <summary>
        /// 获取组织名称信息
        /// </summary>
        /// <param name="orgId">组织ID</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>组织基础数据缓存模型</returns>
        public async Task<OrgBasicDataCacheModel> GetOrgNameAsync(long orgId, CancellationToken cancellationToken = default)
        {
            var org = await GetOrgByKeyAsync(orgId, cancellationToken);
            return org == null ? new OrgBasicDataCacheModel(string.Empty, orgId.ToString()) : new OrgBasicDataCacheModel(org.Name ?? string.Empty, orgId.ToString());
        }

        /// <summary>
        /// 获取部门名称字典
        /// </summary>
        /// <param name="orgId">组织ID</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>部门ID和名称的字典</returns>
        public async Task<IReadOnlyDictionary<long, OrgBasicDataCacheModel>> GetDepartmentNamesAsync(long orgId, CancellationToken cancellationToken = default)
        {
            if (orgId <= 0)
                throw new ArgumentException("Invalid orgId", nameof(orgId));

            var items = await _cacheManager.GetAsync(
                CacheKeys.GetOrgDepartmentsKey(orgId),
                async () =>
                {
                    try
                    {
                        return await LoadDepartmentNamesAsync(orgId, cancellationToken);
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError(ex, "Error getting department names for orgId: {OrgId}", orgId);
                        return null;
                    }
                },
                CacheKeys.CreateOrgBasicDataCacheOptions(),
                cancellationToken);

            return items ?? new Dictionary<long, OrgBasicDataCacheModel>();
        }

        /// <summary>
        /// 获取岗位名称字典
        /// </summary>
        /// <param name="orgId">组织ID</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>岗位ID和名称的字典</returns>
        public async Task<IReadOnlyDictionary<long, OrgBasicDataCacheModel>> GetDutyNamesAsync(long orgId, CancellationToken cancellationToken = default)
        {
            if (orgId <= 0)
                throw new ArgumentException("Invalid orgId", nameof(orgId));

            var items = await _cacheManager.GetAsync(
                CacheKeys.GetOrgDutiesKey(orgId),
                async () =>
                {
                    try
                    {
                        return await LoadDutyNamesAsync(orgId, cancellationToken);
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError(ex, "Error getting duty names for orgId: {OrgId}", orgId);
                        return null;
                    }
                },
                CacheKeys.CreateOrgBasicDataCacheOptions(),
                cancellationToken);

            return items ?? new Dictionary<long, OrgBasicDataCacheModel>();
        }

        /// <summary>
        /// 移除部门缓存
        /// </summary>
        /// <param name="orgId">组织ID</param>
        /// <returns>表示异步操作的任务</returns>
        public Task RemoveDepartmentCacheAsync(long orgId)
        {
            if (orgId <= 0)
                throw new ArgumentException("Invalid orgId", nameof(orgId));

            _logger.LogDebug("Removing department cache for orgId: {OrgId}", orgId);
            return _cacheManager.RemoveAsync(CacheKeys.GetOrgDepartmentsKey(orgId));
        }

        /// <summary>
        /// 移除岗位缓存
        /// </summary>
        /// <param name="orgId">组织ID</param>
        /// <returns>表示异步操作的任务</returns>
        public Task RemoveDutyCacheAsync(long orgId)
        {
            if (orgId <= 0)
                throw new ArgumentException("Invalid orgId", nameof(orgId));

            _logger.LogDebug("Removing duty cache for orgId: {OrgId}", orgId);
            return _cacheManager.RemoveAsync(CacheKeys.GetOrgDutiesKey(orgId));
        }

        /// <summary>
        /// 移除组织缓存
        /// </summary>
        /// <param name="orgId">组织ID</param>
        /// <returns>表示异步操作的任务</returns>
        public Task RemoveOrgCacheAsync(long orgId)
        {
            if (orgId <= 0)
                throw new ArgumentException("Invalid orgId", nameof(orgId));

            _logger.LogDebug("Removing organization cache for orgId: {OrgId}", orgId);
            return _cacheManager.RemoveAsync(CacheKeys.GetOrgKey(orgId));
        }

        /// <summary>
        /// 清除组织相关所有缓存
        /// </summary>
        /// <param name="orgId"></param>
        /// <returns></returns>
        public Task RemoveOrgAllCacheAsync(long orgId)
        {
            if (orgId <= 0)
                throw new ArgumentException("Invalid orgId", nameof(orgId));

            _logger.LogDebug("Removing all caches for orgId: {OrgId}", orgId);
            return _cacheManager.RemoveByPrefixAsync(CacheKeys.GetOrgAllKeyPrefix(orgId));
        }

        #endregion IOrgBasicDataCacheService

        /// <summary>
        /// 从数据库加载部门数据
        /// </summary>
        /// <param name="orgId">组织ID</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>部门数据字典</returns>
        private async Task<IReadOnlyDictionary<long, OrgBasicDataCacheModel>> LoadDepartmentNamesAsync(long orgId, CancellationToken cancellationToken)
        {
            _logger.LogDebug("Getting department names from database for orgId: {OrgId}", orgId);

            // 从数据库查询部门信息
            var query = _context.Query<Department>()
                .Where(d => d.OrgId == orgId)
                .Select(d => new { d.Id, d.Name, d.State, d.ParentId });

            var list = await _context.ToListAsync(query, cancellationToken);

            // 转换为字典
            var departments = list.ToDictionary(
                d => d.Id,
                d => new OrgBasicDataCacheModel(d.Name ?? string.Empty, d.Id.ToString())
                {
                    ParentValue = $"{d.ParentId}",
                    States = d.State
                }
            );

            _logger.LogDebug("Retrieved {Count} departments for orgId: {OrgId}", departments.Count, orgId);

            return departments;
        }

        /// <summary>
        /// 从数据库加载岗位数据
        /// </summary>
        /// <param name="orgId">组织ID</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>岗位数据字典</returns>
        private async Task<IReadOnlyDictionary<long, OrgBasicDataCacheModel>> LoadDutyNamesAsync(long orgId, CancellationToken cancellationToken)
        {
            _logger.LogDebug("Getting duty names from database for orgId: {OrgId}", orgId);

            var query = _context.Query<Duty>()
                .Where(d => d.OrgId == orgId)
                .Select(d => new { d.Id, d.Name, d.State });

            var list = await _context.ToListAsync(query, cancellationToken);

            var duties = list.ToDictionary(
                d => d.Id,
                d => new OrgBasicDataCacheModel(d.Name ?? string.Empty, d.Id.ToString())
                {
                    States = d.State
                }
            );

            _logger.LogDebug("Retrieved {Count} duties for orgId: {OrgId}", duties.Count, orgId);

            return duties;
        }

        /// <summary>
        /// 从数据库加载组织数据
        /// </summary>
        /// <param name="orgId">组织ID</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>组织基础数据缓存模型</returns>
        private async Task<OrganizationInfo?> LoadOrgAsync(long orgId, CancellationToken cancellationToken)
        {
            _logger.LogDebug("Getting organization info from database for orgId: {OrgId}", orgId);

            var query = _context.Query<Organization>()
                .Where(o => o.Id == orgId)
                .Select(f => new { f.Id, f.IdentificationCode, f.Name, f.ParentId, f.State, f.LastModificationTime });

            var org = await _context.FirstOrDefaultAsync(query, cancellationToken);

            if (org == null)
            {
                _logger.LogWarning("Organization not found for orgId: {OrgId}", orgId);
                return null;
            }

            return new OrganizationInfo
            {
                OrgId = org.Id,
                Code = org.IdentificationCode,
                Name = org.Name,
                ParentId = org.ParentId.ToString(),
                IsActive = org.State == EntityStates.Normal,
                LastModified = org.LastModificationTime,
                Source = "UPMS",
                ExternalId = org.Id.ToString()
            };
        }
    }
}